const automator = require('miniprogram-automator');
const fs = require('fs');
const path = require('path');

const watchApp = function (ipcMain) {
	let miniProgram;
	let page;
	let startApp = async (event, config) => {
		const { path } = config;
		// filePath是从渲染进程返回来的数据
		console.log("【ipcMain】收到消息：", path);
		miniProgram = await automator.launch({
			projectPath: path,
		});
		// 初始化页面
		page = await miniProgram.currentPage()
		// 获取应用截屏
		event.reply('launch-finish')
	}
	/**
	 * 验证是否启动APP
	 */
	const check = async (event, pagePath) => {
		if (!miniProgram || !page) {
			event.reply('app-not-start', '', 'app未启动');
			return Promise.reject()
		}
		const currentPage = await miniProgram.currentPage();
		if (pagePath && (pagePath != `/${currentPage.path}`)) {
			if (miniProgram.currentPage())
				page = await miniProgram.reLaunch(pagePath)
			await page.waitFor(500)
			return Promise.reject();
		}
		return Promise.resolve()
	}
	/**
	 * 查找元素
	 * @param {*} type 
	 * @param {*} selector 
	 * @param {*} index 
	 */
	const findElement = async (type, selector, index) => {
		try {
			if (type == 'class') {
				let elements = await page.$$('.' + selector)
				let element = elements[index];
				return element;
			}
			return null;
		} catch (e) {
			return null;
		}
	}
	/**
	 * 延迟
	 * @param {*} time 
	 */
	const delay = time => {
		return new Promise((resolve) => {
			setTimeout(() => {
				resolve()
			}, time)
		})
	}
	/**
	 * 执行异步函数
	 * @param {*} arr 
	 */
	const runAsync = async (arr) => {
		if (!arr.length) return;
		let fn = arr.shift();
		await fn.call(null)
		runAsync(arr)
	}


	ipcMain.on('launch-app', startApp)
	// 执行验证
	ipcMain.on('validate', async (event, ele) => {
		const { className, callback } = ele;
		if (!page) {
			console.log("page 已经失效");
			startApp('e', "restart app");
			return;
		}
		let element = await page.$(`.${className}`);
		let text = await element[ele.validateType]();
		return text == ele.validateContent
	})
	// 执行事件
	ipcMain.on('get-xml', async (event, ele) => {
		// filePath是从渲染进程返回来的数据
		// const { className } = ele;
		await check(event)
		// if (!page) {
		// 	miniProgram.currentPage().then(res => {
		// 		page = res;
		// 		event.reply('launch-finish')
		// 	})
		// 	return event.reply('get-xml-finish', '', 'app未启动');
		// }
		let element = await page.$('page')
		if (!element) {
			miniProgram.currentPage().then(res => {
				page = res;
				event.reply('launch-finish')
			})
			return event.reply('get-xml-finish', '', 'ele 查找失败');
		}
		let wxml = await element.wxml();
		let currentPage = await miniProgram.currentPage();
		event.reply('get-xml-finish', { path: currentPage.path, wxml });
	})
	// 执行事件
	ipcMain.on('exec-event', async (event, ele) => {
		// filePath是从渲染进程返回来的数据
		const { className } = ele;
		if (!page) {
			console.log("page 已经失效");
			startApp('e', "restart app");
			return;
		}
		const element = await page.$(`.${className}`)
		// const y = (await element.scrollHeight()) - 50
		// await element.scrollTo(0, y)
		element && element[ele.event](...ele.params).then(err => {
			if (!err) {
				console.log(`执行${ele.event}成功,执行对象：${className},参数：${ele.params}`);
			}

		}).catch(e => {
			console.log("执行错误:", e)
		})
	})
	/*
	 *  查找元素相信信息
	 */
	ipcMain.on('element-info', async (event, ele) => {

		const { className, index } = ele;
		let elements = await page.$$('.' + className)
		let element = elements[index];
		let property = {};
		if (!element) {
			return event.reply('element-info-finish', '', 'ele 查找失败');
		}
		if (ele.type == 'input') {
			property.value = await element.property('value');
		} else if (ele.type == 'scroll-view') {
			property.scrollWidth = await element.scrollWidth()
			property.scrollHeight = await element.scrollHeight()
		} else if (ele.type == 'image') {
			property.src = await element.attribute('src')
		} {
			const { width, height } = await element.size();
			property.width = width;
			property.height = height;
		}
		//  if (ele.type == 'text') {
		// } 
		property.text = await element.text();
		const offset = await element.offset();
		property.x = offset.lefy;
		property.y = offset.top;
		property.tagName = element.tagName;
		property.className = await element.attribute('class')
		let scrollElement = await page.$('scroll-view');
		if (scrollElement) {
			scrollElement.scrollTo(0, property.y - 100);
		} else {
			miniProgram.pageScrollTo(property.y - 100);
		}
		event.reply('element-info-finish', property)

	})
	/**
	 * 保存项目
	 */
	ipcMain.on('save-project', async (event, string) => {
		// const projects = JSON.parse(string);
		const projectPath = path.resolve(__dirname, '../data/project.json');
		fs.writeFileSync(projectPath, string)
		event.reply('save-project-success');
	})
	/**
	 * 初始化项目数据
	 */
	ipcMain.on('init-data', async (event, string) => {
		// const projects = JSON.parse(string);
		const projectPath = path.resolve(__dirname, '../data/project.json');
		const data = fs.readFileSync(projectPath, 'utf-8');
		event.reply('init-data-success', data);
	})
	/**
	 * 执行测试用例
	 */
	ipcMain.on('run-test', async (event, test) => {
		const { title, pagePath, events = [] } = test;
		console.log(`开始切换页面路径：${pagePath}`);
		console.log(`开始执行测试用例：${title}`);
		await check(event, pagePath);
		let arr = [];
		events.forEach((item, number) => {
			let fn = async () => {

				try {
					const element = await findElement('class', item.selectElement.className, item.selectElement.index);
					if (!element) {
						event.reply('run-test-process', {
							data: {
								index: item.selectElement.index
							},
							msg: '未找到元素'
						})
						throw Error("没有找到元素");
					}
					try {
						let params = item.params.split(',');
						const err = await element[item.eventType](...params);
						if (!err) {
							console.log(`执行${item.event}成功,执行对象：${item.className},参数：${item.params}`);
						}
						event.reply('run-test-process', {
							data: {
								index: number
							},
							msg: ''
						})
						await delay(1000);
					} catch (e) {
						console.log("执行错误:", e)
						event.reply('run-test-process', {
							fail: true,
							data: {
								index: number
							},
							msg: e
						})
					}

				} catch (e) {

				}
			}
			arr.push(fn);
		})
		runAsync(arr);
		// events.forEach(async item => {
		// })
	})
}

module.exports = watchApp;